package com.goertek.easyface.device;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.goertek.easyface.entity.AAcsFaceDeviceConfig;
import com.goertek.easyface.service.AcsDataService;
import com.goertek.easyface.service.DeviceInfoService;
import com.goertek.easyface.utils.Const;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: easy-face
 * @description: 设备集合
 * @author: devin.duj
 * @create: 2024-03-28 15:35
 */
@Slf4j
@Component
@Data
public class DeviceStore {
    @Autowired
    private DeviceInfoService deviceInfoService;
    @Autowired
    private AcsDataService acsDataService;

    @Value("${easy-face.image-dir}")
    private String imageDir;  //图片存储文件夹

    private Map<String, AAcsFaceDeviceConfig> deviceInfoMap;  //IP -> DeviceInfo
    private Map<String, DeviceModal> deviceModalMap = new HashMap<>();  //注册的设备 IP -> DeviceInfo
    private Map<String, DeviceModal> reConnectDeviceMap = new HashMap<>();  //启动失败，需要重启的设备 IP -> DeviceInfo

    //从数据库中查询可用的设备
    @PostConstruct
    public void init() {
        List<AAcsFaceDeviceConfig> list = deviceInfoService.list(new LambdaQueryWrapper<AAcsFaceDeviceConfig>().eq(AAcsFaceDeviceConfig::getDeleteFlag, Const.NOT_DELETE));
        deviceInfoMap = list.stream().collect(Collectors.toMap(AAcsFaceDeviceConfig::getDeviceIp, o -> o));
    }

    //将内存中已经注册的设备，仅同步设备名称、Door名称，Websocket配置地址、部门名称、人脸区域门组信息，这种配置信息
    public void syncDatabase(){
        List<AAcsFaceDeviceConfig> list = deviceInfoService.list(new LambdaQueryWrapper<AAcsFaceDeviceConfig>().eq(AAcsFaceDeviceConfig::getDeleteFlag, Const.NOT_DELETE));
        for(AAcsFaceDeviceConfig config : list){
            if(deviceModalMap.get(config.getDeviceIp()) != null){
                DeviceModal modal = deviceModalMap.get(config.getDeviceIp());
                AAcsFaceDeviceConfig deviceInfo = modal.getDeviceInfo();
                deviceInfo.setDeptName(config.getDeptName());
                deviceInfo.setAreaName(config.getAreaName());
                deviceInfo.setDeviceName(config.getDeviceName());
                deviceInfo.setDoorName(config.getDoorName());
                deviceInfo.setWebsocketAddress(config.getWebsocketAddress());
            }
        }
    }

    //批量登录+订阅智能事件
    public void startBatch(boolean isRefresh) {
        Collection<AAcsFaceDeviceConfig> list =  deviceInfoMap.values();
        if(isRefresh){  //如果需要刷新数据库最新的设备，将不在内存中的重新进行启动
            List<String> oldIp = deviceModalMap.values().stream().map(o -> o.getDeviceInfo().getDeviceIp()).collect(Collectors.toList());
            list = deviceInfoService.list(new LambdaQueryWrapper<AAcsFaceDeviceConfig>()
                    .eq(AAcsFaceDeviceConfig::getDeleteFlag, Const.NOT_DELETE)
                    .notIn(oldIp.size() > 0 , AAcsFaceDeviceConfig::getDeviceIp , oldIp));
        }
        if(list.size() == 0){
            System.out.println("没有需要启动的设备");
        }
        for(AAcsFaceDeviceConfig deviceInfo : list){
            try{
                DeviceModal deviceModal = new DeviceModal(deviceInfo,imageDir,acsDataService);
                //注册到deviceModalMap 中
                deviceModalMap.put(deviceInfo.getDeviceIp(),deviceModal);
                if(deviceModal.login()){ //登录成功后，更新登录在线状态
                    deviceInfo.setLoginStatus(Const.LOGIN); //更新内存数据
                    deviceInfoService.update(new LambdaUpdateWrapper<AAcsFaceDeviceConfig>()
                            .set(AAcsFaceDeviceConfig::getLoginStatus,Const.LOGIN).eq(AAcsFaceDeviceConfig::getId,deviceInfo.getId()));
                    System.out.println(deviceInfo.getDeviceName()+"设备["+deviceInfo.getDeviceIp()+"]登录成功");
                    //Thread.sleep(3000);  //休眠3秒
                    if(deviceModal.startSubscribe()){ //订阅智能时间后更新订阅状态
                        deviceInfo.setSubscribeStatus(Const.SUBSCRIBE); //更新内存数据
                        deviceInfoService.update(new LambdaUpdateWrapper<AAcsFaceDeviceConfig>()
                                .set(AAcsFaceDeviceConfig::getSubscribeStatus,Const.SUBSCRIBE).eq(AAcsFaceDeviceConfig::getId,deviceInfo.getId()));
                        System.out.println(deviceInfo.getDeviceName()+"设备["+deviceInfo.getDeviceIp()+"]订阅门禁事件成功");
                        //Thread.sleep(3000);  //休眠3秒
                    }
                }else{
                    deviceInfo.setLoginStatus(Const.NOT_LOGIN); //更新内存数据
                    deviceInfo.setSubscribeStatus(Const.NOT_SUBSCRIBE); //更新内存数据
                    deviceInfoService.update(new LambdaUpdateWrapper<AAcsFaceDeviceConfig>()
                            .set(AAcsFaceDeviceConfig::getSubscribeStatus,Const.NOT_SUBSCRIBE)
                            .set(AAcsFaceDeviceConfig::getLoginStatus,Const.NOT_LOGIN)
                            .eq(AAcsFaceDeviceConfig::getId,deviceInfo.getId()));
                    //如果一开始就没有连上的，是需要通过定时任务重新建立链接的，SDK并不会对这种情况进行处理
                    reConnectDeviceMap.put(deviceInfo.getDeviceIp(),deviceModal);
                }
            }catch (Exception e){
                log.error("启动 "+deviceInfo.getDeviceName()+" 时异常",e);
            }
        }
    }

    //如果一开始就没有连上的，是需要通过定时任务重新建立链接的，SDK并不会对这种情况进行处理
    //一开始连上的，后续再断开，SDK自己会进行重连，不用我们管
    public void reConnect(){
        List<String> successKeyList = new ArrayList<>();
        for (Map.Entry <String, DeviceModal> entry : reConnectDeviceMap.entrySet()) {
            log.info("准备重连设备- " + entry.getKey());
            if(start(entry.getKey())){
                successKeyList.add(entry.getKey());
                log.info("重连设备成功！ " + entry.getKey());
            }else{
                log.info("重连设备失败！ " + entry.getKey());
            }
        }
        for(String key : successKeyList){
            reConnectDeviceMap.remove(key);
        }
    }

    //批量登出+取消订阅
    public void stopBatch(){
        for(DeviceModal deviceModal : deviceModalMap.values()){
            AAcsFaceDeviceConfig deviceInfo = deviceModal.getDeviceInfo();
            try{
                deviceModal.logout(); //登出后更新离线状态和取消订阅状态
                deviceInfo.setLoginStatus(Const.NOT_LOGIN); //更新内存数据
                deviceInfo.setSubscribeStatus(Const.NOT_SUBSCRIBE); //更新内存数据
                deviceInfoService.update(new LambdaUpdateWrapper<AAcsFaceDeviceConfig>()
                        .set(AAcsFaceDeviceConfig::getSubscribeStatus,Const.NOT_SUBSCRIBE)
                        .set(AAcsFaceDeviceConfig::getLoginStatus,Const.NOT_LOGIN)
                        .eq(AAcsFaceDeviceConfig::getId,deviceInfo.getId()));
                System.out.println(deviceInfo.getDeviceName()+"设备["+deviceInfo.getDeviceIp()+"]取消订阅事件，并登出成功");
                //Thread.sleep(3000);  //休眠3秒
            }catch (Exception e){
                log.error("停止 "+ deviceInfo.getDeviceIp()+" 时异常",e);
            }
        }
    }

    //获取已经注册到内存中的设备信息
    public List<AAcsFaceDeviceConfig> getDeviceInfoList(){
        return deviceModalMap.values().stream().map(o -> o.getDeviceInfo()).collect(Collectors.toList());
    }

    //将已经注册到内存的设备移除（取消订阅并登出） 【remove ip】
    public void remove(String deviceIp){
        DeviceModal deviceModal = deviceModalMap.get(deviceIp);
        if(deviceModal == null){
            System.out.println("设备["+deviceIp+"]未注册到内存中，请执行 【register ip】 指令将数据库库中配置的设备注册到内存中");
        }else{
            if(stop(deviceIp)){
                deviceModalMap.remove(deviceIp);
                System.out.println("设备["+deviceIp+"]从内存中移除成功");
            }
        }
    }

    //将数据库中配置的设备注册到内存中 【register ip】
    public boolean register(String deviceIp){
        DeviceModal exist = deviceModalMap.get(deviceIp);
        if(exist != null){
            System.out.println("设备["+deviceIp+"]已经注册过，请勿重复操作！");
            return false;
        }
        AAcsFaceDeviceConfig deviceInfo = deviceInfoService.getOne(new LambdaQueryWrapper<AAcsFaceDeviceConfig>()
                .eq(AAcsFaceDeviceConfig::getDeviceIp, deviceIp)
                .eq(AAcsFaceDeviceConfig::getDeleteFlag, Const.NOT_DELETE));
        if(deviceInfo == null){
            System.out.println(deviceInfo.getDeviceName()+"设备["+deviceIp+"]未在数据库中配置信息！");
        }else{
            DeviceModal deviceModal = new DeviceModal(deviceInfo,imageDir,acsDataService);
            //注册到deviceModalMap 中
            deviceModalMap.put(deviceInfo.getDeviceIp(),deviceModal);
            System.out.println(deviceInfo.getDeviceName()+"设备["+deviceIp+"]注册成功，可执行 【start ip】 指令登录和订阅门禁事件！");
            return true;
        }
        return false;
    }

    //单个登录 + 注册  【start ip】
    public boolean start(String deviceIp){
        DeviceModal deviceModal = deviceModalMap.get(deviceIp);
        if(deviceModal == null){
            System.out.println("设备["+deviceIp+"]未注册到内存中，请执行 【register ip】 指令将数据库库中配置的设备注册到内存中");
        }else{
            AAcsFaceDeviceConfig deviceInfo = deviceModal.getDeviceInfo();
            if(deviceModal.login()){ //登录成功后，更新登录在线状态
                deviceInfo.setLoginStatus(Const.LOGIN); //更新内存数据
                deviceInfoService.update(new LambdaUpdateWrapper<AAcsFaceDeviceConfig>()
                        .set(AAcsFaceDeviceConfig::getLoginStatus,Const.LOGIN).eq(AAcsFaceDeviceConfig::getId,deviceInfo.getId()));
                System.out.println(deviceInfo.getDeviceName()+"设备["+deviceIp+"]登录成功");
                if(deviceModal.startSubscribe()){ //订阅智能时间后更新订阅状态
                    deviceInfo.setSubscribeStatus(Const.SUBSCRIBE); //更新内存数据
                    deviceInfoService.update(new LambdaUpdateWrapper<AAcsFaceDeviceConfig>()
                            .set(AAcsFaceDeviceConfig::getSubscribeStatus,Const.SUBSCRIBE).eq(AAcsFaceDeviceConfig::getId,deviceInfo.getId()));
                    System.out.println(deviceInfo.getDeviceName()+"设备["+deviceIp+"]订阅门禁事件成功");
                    return true;
                }
            }
        }
        return false;
    }

    //单个登出+取消订阅 【stop ip】
    public boolean stop(String deviceIp){
        DeviceModal deviceModal = deviceModalMap.get(deviceIp);
        if(deviceModal == null){
            System.out.println("设备["+deviceIp+"]未注册到内存中，请执行 【register ip】 指令将数据库库中配置的设备注册到内存中");
        }else{
            AAcsFaceDeviceConfig deviceInfo = deviceModal.getDeviceInfo();
            deviceModal.logout(); //登出后更新离线状态和取消订阅状态
            deviceInfo.setLoginStatus(Const.NOT_LOGIN); //更新内存数据
            deviceInfo.setSubscribeStatus(Const.NOT_SUBSCRIBE); //更新内存数据
            deviceInfoService.update(new LambdaUpdateWrapper<AAcsFaceDeviceConfig>()
                    .set(AAcsFaceDeviceConfig::getSubscribeStatus,Const.NOT_SUBSCRIBE)
                    .set(AAcsFaceDeviceConfig::getLoginStatus,Const.NOT_LOGIN)
                    .eq(AAcsFaceDeviceConfig::getId,deviceInfo.getId()));
            System.out.println(deviceInfo.getDeviceName()+"设备["+deviceIp+"]取消订阅事件，并登出成功");
            return true;
        }
        return false;
    }

    //根据IP获取设备配置信息
    public AAcsFaceDeviceConfig getDeviceConfigByIp(String ip){
        if(deviceModalMap.containsKey(ip)){
            return deviceModalMap.get(ip).getDeviceInfo();
        }
        return null;
    }
}